#pragma once
#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>

const std::string HttpSeq = "\r\n";
const std::string homepage = "index.html";
const std::string wwwroot = "./wwwroot";

class HttpRequest
{
    // http 报文
    std::string _req_line; // 请求行
    std::vector<std::string> _req_header;
    std::string _req_blank;
    std::string _req_content;

    std::string _suffix; // 请求资源的后缀

    // 解析后的内容
    std::string _method;
    std::string _url;
    std::string _http_version;
    std::string _path;

public:
    HttpRequest() : _req_blank(HttpSeq), _path(wwwroot) {}
    ~HttpRequest() {}

    void ParseRequest()
    {
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _http_version;

        if (_url == "/")
        {
            // ./wwwroot  /  index.html
            _path += "/" + homepage;
        }
        else
        {
            _path += _url;
        }
    }
    void ParseSuffix()
    {
        auto pos = _path.rfind(".");
        if (pos == std::string::npos)
            _suffix = ".html";
        else
            _suffix = _path.substr(pos); // 从 pos 一直截取到结尾
    }
    void Parse()
    {
        ParseRequest();
        // 获取后缀
        ParseSuffix();
    }

    bool Getline(std::string &str, std::string *out)
    {
        auto pos = str.find(HttpSeq);
        if (pos == std::string::npos)
            return false;
        *out = str.substr(0, pos);          // 入股是空行 , 找到 \r\n 后，发现下标pos 为 0，那么 *out 为""
        str.erase(0, pos + HttpSeq.size()); // 在将 \r\n 删除
        return true;
    }

    void Degub()
    {
        std::cout << "-------------------- >>>  Http Test" << std::endl;
        std::cout << "_req_line: " << _req_line << std::endl;
        for (auto &line : _req_header)
        {
            std::cout << "--> " << line << std::endl;
        }
        // std::cout << "_req_blank: " << _req_blank << std::endl;
        std::cout << "Method: " << _method << std::endl;
        std::cout << "Url: " << _url << std::endl;
        std::cout << "_http_version: " << _http_version << std::endl;
    }

    void Deserialize(std::string &request)
    {
        std::string line;
        bool ok = Getline(request, &line);
        if (!ok)
            return;       // 出错返回
        _req_line = line; // 报头请求信息赋值给 _req_line

        while (true)
        {
            bool ok = Getline(request, &line);
            if (ok)
            {
                if (line.empty()) // 解析没有问题，但是是空的，说明只剩下 正文内容了
                {
                    _req_content = request; // 将剩下的正文赋值给 _req_content
                    break;
                }
                else
                {
                    // line 不是空行，说明是报头内容，push到 _req_header
                    _req_header.emplace_back(line);
                }
            }
            else
            {
                // ok 失败
                break; // 没有/n , 退出
            }
        }
    }

    std::string GetFileContentHeader(const std::string &path)
    {

        // std::ifstream in(path, std::ios::binary); // 以二进制读取文件
        // if (!in.is_open())                        // 如果文件打开失败，直接返回
        //     return "";

        // std::string content, line;
        // while (getline(in, line))
        //     content += line;
        // // in >> content;
        // in.close();
        // return content;

        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            
             return "";
        }
        // 打开文件后，将文件流移动到文件的最结尾
        in.seekg(0, in.end);
        int filesize = in.tellg(); // 读取文件的偏移量，因为我们移动到结尾，读取到的就是文件的总大小

        // 读取到大小后，再将文件流移动到 文件的最开始
        in.seekg(0, in.beg);

        std::string content;
        // 将字符串的大小调整成文件的大小
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize); // 从content的起始位置开始读取，读取filesize个字节

        // 上面的步骤最好用vector来实现
        // std::vector<char> content(filesize);
        // in.read(content.data(),filesize);  // content.data() 容器的起始地址
        // // read 方法 从content容器的起始地址开始填充，填充filesize大小

        in.close();
        return content;
    }

    // 获取正常页面
    std::string GetFileContent(const std::string &path)
    {
        return GetFileContentHeader(path);
    }

    // 获取 404 页面
    std::string Get_404_Content()
    {
        return GetFileContentHeader(wwwroot+"/404.html");
    }

    std::string Url()
    {
        return _url;
    }

    std::string Path()
    {
        return _path;
    }

    std::string Suffix()
    {
        return _suffix;
    }

};

const std::string BlankSeq = " ";
const std::string LineSeq = "\r\n";

class HttpResponse
{
    std::string _status_line;              // "Http/1.0 200 OK\r\n";
    std::vector<std::string> _resp_header; // 总内容
    std::string _resp_blank;
    std::string _resp_content; // body

    // 设置网页的报头信息
    std::string _http_version;
    int _status_code;
    std::string _status_code_desc;

public:
    HttpResponse() : _http_version("HTTP/1.0"), _status_code(200), _status_code_desc("OK"), _resp_blank(LineSeq)
    {
    }
    ~HttpResponse() {}

    void SetCode(int code)
    {
        _status_code = code;
    }

    void SetDesc(const std::string &desc)
    {
        _status_code_desc = desc;
    }

    void AddHeader(const std::string &header)
    {
        _resp_header.push_back(header);
    }

    void AddContent(const std::string &content)
    {
        _resp_content = content;
    }

    // 序列化
    std::string Serialize()
    {
        std::string response_str = _status_line;
        for (auto &line : _resp_header)
            response_str += line;

        response_str += _resp_blank;  // 加上 "\r\n"
        response_str += _resp_content;

        return response_str;
    }

    void Make_Status_Line()
    {
        // 设置状态行  "Http/1.0 200 OK\r\n";
        _status_line = _http_version + BlankSeq + std::to_string(_status_code) + \
         BlankSeq + _status_code_desc + LineSeq;
    }
};